import angular from 'angular';

ngToastService.$inject = ['$timeout'];

function ngToastService($timeout) {
  var counter = 0;
  var toasts = [];
  var defaults = {
    duration: 3000,
    dismissible: true,
    type: 'info',
    maxToasts: 5
  };

  function normalizeOptions(message, opts) {
    var options = {};

    if (angular.isObject(message)) {
      options = angular.extend({}, defaults, message);
    } else {
      options = angular.extend({}, defaults, opts, { message: message });
    }

    options.id = 'toast_' + (++counter);
    options.createdAt = Date.now();
    options.type = options.type || 'info';
    options.dismissible = options.dismissible !== false;

    if (!angular.isNumber(options.duration) || options.duration < 0) {
      options.duration = defaults.duration;
    }

    return options;
  }

  function enforceLimit(maxToasts) {
    if (!maxToasts || maxToasts <= 0) {
      return;
    }

    while (toasts.length > maxToasts) {
      toasts.shift();
    }
  }

  function scheduleAutoDismiss(toast) {
    if (!toast.duration) {
      return;
    }

    toast.timeoutPromise = $timeout(function() {
      remove(toast.id);
    }, toast.duration);
  }

  function show(message, opts) {
    var toast = normalizeOptions(message, opts);
    var maxToasts = toast.maxToasts || defaults.maxToasts;

    toasts.push(toast);
    enforceLimit(maxToasts);
    scheduleAutoDismiss(toast);

    return toast.id;
  }

  function remove(id) {
    for (var i = 0; i < toasts.length; i++) {
      if (toasts[i].id === id) {
        if (toasts[i].timeoutPromise) {
          $timeout.cancel(toasts[i].timeoutPromise);
        }
        toasts.splice(i, 1);
        break;
      }
    }
  }

  function clearAll() {
    toasts.forEach(function(item) {
      if (item.timeoutPromise) {
        $timeout.cancel(item.timeoutPromise);
      }
    });

    toasts.length = 0;
  }

  function createTyped(type) {
    return function(message, opts) {
      var options = angular.extend({}, opts, { type: type });
      return show(message, options);
    };
  }

  return {
    toasts: toasts,
    show: show,
    success: createTyped('success'),
    info: createTyped('info'),
    warning: createTyped('warning'),
    danger: createTyped('danger'),
    remove: remove,
    clearAll: clearAll
  };
}

export default ngToastService;
